package nz.ac.massey.spidernetpn.gui;

import nz.ac.massey.spidernetpn.webcrawler.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JRootPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.validator.UrlValidator;

import edu.uci.ics.jung.algorithms.layout.AbstractLayout;
import edu.uci.ics.jung.algorithms.layout.FRLayout2;
import edu.uci.ics.jung.algorithms.layout.util.Relaxer;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.ObservableGraph;
import edu.uci.ics.jung.graph.event.GraphEvent;
import edu.uci.ics.jung.graph.event.GraphEventListener;
import edu.uci.ics.jung.graph.util.Graphs;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.Renderer;

public class MainGui extends JApplet {

	private Graph<String, Number> g = null;
	private AbstractLayout<String, Number> layout = null;
	Timer timer;
	boolean done;
	private static VisualizationViewer<String, Number> vv = null;
	// boolean go=false;

	public double scale = 1.0;
	public int min = 1, max = 36, inc = 5;

	JSlider slider;
	JLabel label;
	Thread loadThread;
	Object lock = new Object();
	boolean shouldStop = false;
	JTextField progressTextField;
	JProgressBar progressBar;
	String str = "";

	public void init() {
		// create a graph
		Graph<String, Number> ig = Graphs
				.<String, Number> synchronizedDirectedGraph(new DirectedSparseGraph<String, Number>());
		ObservableGraph<String, Number> og = new ObservableGraph<String, Number>(
				ig);
		og.addGraphEventListener(new GraphEventListener<String, Number>() {
			public void handleGraphEvent(GraphEvent<String, Number> evt) {
				System.err.println("got " + evt);
			}
		});
		this.g = og;
		// create a graphdraw
		layout = new FRLayout2<String, Number>(g);
		// ((FRLayout)layout).setMaxIterations(200);

		vv = new VisualizationViewer<String, Number>(layout, new Dimension(300,
				300));
		JRootPane rp = this.getRootPane();
		rp.putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);

		getContentPane().setLayout(new BorderLayout());
		getContentPane().setBackground(java.awt.Color.lightGray);
		getContentPane().add(createPanel(), BorderLayout.SOUTH);

		vv.getModel().getRelaxer().setSleepTime(500);
		vv.setGraphMouse(new DefaultModalGraphMouse());
		vv.getRenderer().getVertexLabelRenderer().setPosition(
				Renderer.VertexLabel.Position.CNTR);
		vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
		vv.setForeground(Color.white);
		getContentPane().add(vv);
		timer = new Timer();

	}

	/*
	 * public void start() { validate(); //set timer so applet will change
	 * timer.schedule(new RemindTask(), 1000, 1000); vv.repaint();
	 * 
	 * }
	 */
	String v_prev = null;

	/*
	 * public void process() {
	 * 
	 * try {
	 * 
	 * if (g.getVertexCount() < 10) { layout.lock(true); //add a vertex //String
	 * v1 = new Integer(g.getVertexCount());
	 * 
	 * Relaxer relaxer = vv.getModel().getRelaxer(); relaxer.pause();
	 * g.addVertex(nextURL);
	 * 
	 * // wire it to some edges if (v_prev != null) {
	 * g.addEdge(g.getEdgeCount(), v_prev, nextURL); // let's connect to a
	 * random vertex, too! // int rand = (int) (Math.random()
	 * g.getVertexCount()); //g.addEdge(g.getEdgeCount(), str, rand); }
	 * 
	 * v_prev = nextURL;
	 * 
	 * layout.initialize(); relaxer.resume(); layout.lock(false); } else { done
	 * = true; }
	 * 
	 * } catch (Exception e) { System.out.println(e);
	 * 
	 * } }
	 */

	class RemindTask extends TimerTask {

		public void run() {
			search();

			if (done)
				cancel();

		}
	}

	JTextField urlField;

	//
	// Main
	//
	public static JFrame frame = new JFrame("Web-Clawer");

	// Main Method
	public static void main(String[] args) {

		MainGui and = new MainGui();
		// Construct Frame
		// Set Close Operation to Exit
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		// Add an Editor Panel
		frame.getContentPane().add(new MainGui());
		frame.getContentPane().add(and);
		// if(go){
		and.init();
		// }

		// and.start();
		frame.pack();
		frame.setSize(700, 700);
		// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		// Show Frame
		frame.setVisible(true);
		// Scale test = new Scale(vv);
		// frame.getContentPane().add(test.getSlider(), "Last");
	}

	//
	// Editor Panel
	//

	// Construct an Editor Panel
	public MainGui() {
		// Creates a menubar for a JFrame
		JMenuBar menuBar = new JMenuBar();

		// Add the menubar to the frame
		setJMenuBar(menuBar);

		Thread loadThread;

		// Define and add two drop down menu to the menubar
		JMenu fileMenu = new JMenu("File");
		JMenu editMenu = new JMenu("Edit");
		JLabel Url = new JLabel("Enter url: ");
		urlField = new JTextField();
		urlField.setText("");
		urlField.setColumns(20);

		JButton goButton = new JButton();
		goButton.setLabel("Go");

		menuBar.add(fileMenu);
		menuBar.add(editMenu);
		menuBar.add(Url);
		menuBar.add(urlField);
		menuBar.add(goButton);
		// Create and add simple menu item to one of the drop down menu
		JMenuItem newAction = new JMenuItem("New");
		JMenuItem openAction = new JMenuItem("Open");
		JMenuItem saveAction = new JMenuItem("Save");
		JMenuItem exitAction = new JMenuItem("Exit");
		JMenuItem copyAction = new JMenuItem("Copy");
		JMenuItem cutAction = new JMenuItem("Cut");
		JMenuItem pasteAction = new JMenuItem("Paste");
		fileMenu.add(newAction);
		fileMenu.add(openAction);
		fileMenu.add(saveAction);
		fileMenu.addSeparator();
		fileMenu.add(exitAction);
		editMenu.add(copyAction);
		editMenu.add(cutAction);
		editMenu.add(pasteAction);

		// go button perform search action
		goButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				search();
			}
		});

		exitAction.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
			}
		});
	}

	String nextURL = "";

	public void search() {
		PrototypeWebCrawler WC = new PrototypeWebCrawler();
		UrlValidator VALIDATOR = new UrlValidator();
		Queue<String> WAITING_URLS_QUEUE = new ConcurrentLinkedQueue<String>();

		str = urlField.getText();
		boolean valid = false;
		valid = VALIDATOR.isValid(str);
		if (valid) {
			WAITING_URLS_QUEUE.add(str);
			while (!WAITING_URLS_QUEUE.isEmpty()) {
				nextURL = WAITING_URLS_QUEUE.remove();
				// This method adds more URLs (on the current page) to the
				// WAITING_URLS_QUEUE

				g.addVertex(nextURL);
				if (v_prev != null) {
					g.addEdge(g.getEdgeCount(), v_prev, nextURL);
				}

				v_prev = nextURL;
				vv.repaint();

				WC.processUrl(nextURL);

			}

		}
		// Error box message
		else {
			JOptionPane.showMessageDialog(frame,
					"Please enter URL with correct format start with http://",
					"Error", JOptionPane.ERROR_MESSAGE);
		}

	}

	public class MyChangeAction implements ChangeListener {
		public void stateChanged(ChangeEvent e) {
			int value = slider.getValue();
			scale = (value + 4) / 20.0;
			repaint();
		}
	}

	public Hashtable getLabelTable(int min, int max, int inc) {
		Hashtable<Integer, JLabel> table = new Hashtable<Integer, JLabel>();
		for (int j = min; j <= max; j += inc) {
			String s = String.format("%.2f", (j + 4) / 20.0);
			table.put(Integer.valueOf(j), new JLabel(s));
		}
		return table;
	}

	public void startLoading() {
		double i = 1;
		if (loadThread == null) {
			loadThread = new LoadThread();
			shouldStop = false;
			loadThread.start();

			validate();
			// set timer so applet will change
			if (i / 2 != 0 & !shouldStop) {
				timer.schedule(new RemindTask(), 1000, 1000);
				// vv.repaint();
			}
			i = i + 1;
		}
	}

	public void stopLoading() {
		synchronized (lock) {
			shouldStop = true;
			lock.notify();
		}
	}

	class LoadThread extends Thread {
		public void run() {
			int min = 0;
			int max = 100;
			progressBar.setValue(min);
			progressBar.setMinimum(min);
			progressBar.setMaximum(max);
			Runnable runner = new Runnable() {
				public void run() {
					int value = progressBar.getValue();
					value++;
					progressBar.setValue(value);
					progressTextField.setText("" + value);
				}
			};
			for (int i = min; i <= max; i++) {
				try {
					SwingUtilities.invokeAndWait(runner);
				} catch (InvocationTargetException e) {
					break;
				} catch (InterruptedException e) {
					// Ignore Exception
				}
				synchronized (lock) {
					if (shouldStop)
						break;
					try {
						lock.wait(100);
					} catch (InterruptedException e) {
						// Ignore Exception
					}
				}
			}
			loadThread = null;
		}
	}

	public JPanel createPanel() {
		slider = new JSlider(min, max, 16);

		slider.addChangeListener(new MyChangeAction());
		slider.setMajorTickSpacing(5);
		slider.setMinorTickSpacing(1);
		slider.setPaintTicks(true);
		slider.setSnapToTicks(true);
		slider.setLabelTable(getLabelTable(min, max, inc));
		slider.setPaintLabels(true);
		slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				int value = slider.getValue();
				scale = (value + 4) / 20.0;
				validate();
				repaint();
			}
		});

		JPanel panel = new JPanel();
		panel.add(slider);
		progressTextField = new JTextField();
		progressBar = new JProgressBar();
		progressBar.setStringPainted(true);

		panel.setLayout(new GridLayout(0, 1));
		panel.add(progressBar);
		panel.add(new JLabel("Load Status"));
		JPanel buttonPanel = new JPanel();
		JButton startButton = new JButton("Start");
		buttonPanel.add(startButton);
		startButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				startLoading();
			}
		});
		JButton stopButton = new JButton("Stop");
		buttonPanel.add(stopButton);
		stopButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stopLoading();
			}
		});
		panel.add(buttonPanel);
		add(panel, BorderLayout.NORTH);
		return panel;
	}

}
